using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using log4net;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ReLogic.Content;
using Terraria;
using Terraria.GameContent;
using Terraria.Localization;
using Terraria.ModLoader.Config.UI;
using Terraria.ModLoader.Core;
using Terraria.UI;

namespace RSCore;

public static class ModHelper
{
	public const string ModFolder = "ReplaceString";

	public const string ModName = "_ReplaceString_";

	public static string ConfigPath => $"{ModFolder}/Config.json";

	public static string ExportPath => $"{ModFolder}/Export";

	public static ILog? Log { get; private set; } = null;

	public static string LogPath => $"{ModFolder}/Log.txt";

	public static string PackagePath => $"{ModFolder}/Packages";

	public static bool SafeMode { get; set; } = false;

	public static void DrawBorder(Rectangle destination, Color color, int width = 1)
	{
		Main.spriteBatch.Draw(TextureAssets.MagicPixel.Value, destination with { Width = width }, color);
		Main.spriteBatch.Draw(TextureAssets.MagicPixel.Value, destination with { Height = width }, color);
		Main.spriteBatch.Draw(TextureAssets.MagicPixel.Value, destination with { Width = width, X = destination.X + destination.Width - width }, color);
		Main.spriteBatch.Draw(TextureAssets.MagicPixel.Value, destination with { Height = width, Y = destination.Y + destination.Height - width }, color);
	}

	public static void ClearStatic(Assembly assembly)
	{
		foreach(var type in assembly.GetTypes())
		{
			foreach(var field in type.GetFields(BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public))
			{
				if (!field.FieldType.IsValueType && field.FieldType != typeof(string) && !field.IsInitOnly)
				{
					field.SetValue(null, null);
				}
			}
		}
	}

	public static float Approach(this float value, float target, float step)
	{
		Debug.Assert(step != 0);
		int sign = Math.Sign(step);
		value += step;
		if(value * sign < target * sign)
		{
			return value;
		}
		else
		{
			return target;
		}
	}

	public static void Error(string key, params object[] args)
	{
		var text = Language.GetTextValue($"Mods.{ModName}.Error.{key}", args);
		Log?.Error(text);
		text = $"[RS](Error) {text}";
		Console.WriteLine(text);
		File.AppendAllText(LogPath, text);
	}

	public static CalculatedStyle GetConfigListDimension()
	{
		var state = new UIModConfig();
		state.OnInitialize();
		state.Recalculate();
		return state.uIPanel._outerDimensions;
	}

	public static CalculatedStyle Fix(this CalculatedStyle style)
	{
		style.X = (int)Math.Round(style.X);
		style.Y = (int)Math.Round(style.Y);
		style.Width = (int)Math.Round(style.Width);
		style.Height = (int)Math.Round(style.Height);
		return style;
	}

	public static List<ModInfo> GetModInfo()
	{
		List<ModInfo> infos = new();
		LocalMod[] array = ModOrganizer.FindMods(false);
		for (int i = 0; i < array.Length; i++)
		{
			var mod = array[i];
			Texture2D icon = Main.Assets.Request<Texture2D>("Images/UI/DefaultResourcePackIcon", AssetRequestMode.ImmediateLoad).Value;
			if (mod.modFile.HasFile("icon.png"))
			{
				using (mod.modFile.Open())
				{
					using Stream stream = mod.modFile.GetStream("icon.png");
					icon = Main.Assets.CreateUntracked<Texture2D>(stream, ".png").Value;
				}
			}
			infos.Add(new ModInfo(icon, mod.Enabled, mod.Name, mod.DisplayName, mod.properties.version));
		}
		return infos;
	}

	/// <summary>
	/// 获取本Mod中的文本
	/// </summary>
	/// <param name="key"> 无Mods.ReplaceString前置的键 </param>
	/// <param name="args"> 格式化参数 </param>
	/// <returns> </returns>
	public static string GetText(string key, params object[] args)
	{
		return Language.GetTextValue($"Mods.{ModName}.{key}", args);
	}

	public static void Info(string key, params object[] args)
	{
		var text = Language.GetTextValue($"Mods.{ModName}.Info.{key}", args);
		Log?.Info(text);
		text = $"[RS](Info) {text}";
		Console.WriteLine(text);
		File.AppendAllText(LogPath, text);
	}

	public static void Init(ILog log)
	{
		Log = log;
	}

	public static void Warn(string key, params object[] args)
	{
		var text = Language.GetTextValue($"Mods.{ModName}.Warn.{key}", args);
		Log?.Warn(text);
		text = $"[RS](Warn) {text}";
		Console.WriteLine(text);
		File.AppendAllText(LogPath, text);
	}
}

public record struct CodeLocation(string Message, [CallerFilePath] string? File = null, [CallerLineNumber] int Line = 0)
{
	public override readonly string ToString() => $"{Message} at File: {File} Line: {Line}";
}